package model.io;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import model.config.Config;
import model.framework.Block;
import model.framework.BlockType;

public class BlockGenerator {
	
	/**
	 * Creates a list of blocks, with size desiredNumberOfBlocks
	 * The type of each block is randomly chosen from types
	 * @param types the types
	 * @param desiredTotalNumberOfBlocks the desired number of blocks
	 * @return a list of blocks
	 */
	public static List<Block> getBlocks( List<BlockType> types, int desiredTotalNumberOfBlocks){
		List<Block> result = new ArrayList<Block>();
		
		/* create desiredTotalNumberOfBlocks of blocks with a type randomly chosen from the list of types */
		for (int i = 0; i < desiredTotalNumberOfBlocks; i++){
			int type = (int) Math.round(Math.random() * types.size() - 0.5);
			result.add(new Block(types.get(type),i));
		}
		
		return result;
	}
	
	/**
	 * Clones each block and returns the list of clones
	 * @param old the list of blocks
	 * @return the list of clones
	 */
	public static List<Block> deepcopyBlockList (List<Block> old){
		List<Block> result = new ArrayList<Block>();
		for (Block b : old){
			Block newBlock = new Block(b.getBlockType(), b.getId());
			result.add(newBlock);
		}
		return result;
	}
	
	/**
	 * Reads all blocks from the given file
	 * @param fileName
	 * @return
	 * @throws IOException if the file contains invalid blocks
	 */
	public static List<BlockType> getBlocksTypesFromFile( String fileName ) throws IOException {
		File file = new File( fileName );
		Config.p("Reading blocks from: " + file.getAbsolutePath());
		List<BlockType> result = new ArrayList<BlockType>();		
		try {
			Scanner scanner = new Scanner( file );
			List<int[]> blockList = new ArrayList<int[]>();
			int[][] blockArray = null;
			int lineLength = 0;
			while( scanner.hasNextLine() ) {					
				String line = scanner.nextLine();
				if (lineLength == 0) {
					lineLength = line.length();
				}
				
				if (line.startsWith("-")) {
					//Config.p("New block");
					lineLength = 0;
					blockArray = new int[blockList.get(0).length][blockList.size()];
					//Config.p("Block array is: " + blockArray.length + " by " + blockArray[0].length);
					for (int y = 0; y < blockList.size(); y++){
						for (int x = 0; x < blockList.get(y).length; x++){
							//Config.p("("+x+","+y+") ");							
							blockArray[x][y] = blockList.get(blockList.size()-1-y)[x];
						}
					}
					BlockType b = new BlockType(blockArray.clone());
					result.add(b);
					blockList.clear();
					blockArray = null;
				} else {
					if (line.length() != lineLength){
						throw new Exception("Not all lines have the same length");
					}
					int[] arrayLine = new int[line.length()];
					for (int i = 0; i < line.length(); i++){
						arrayLine[i] = Integer.parseInt(""+line.charAt(i));
					}
					blockList.add(arrayLine);
				}
			}
			if (result.size() == 0){
				throw new Exception("File contains no blocks");
			}
		} catch( Exception e ) {			
			e.printStackTrace();
			throw new IOException("Block file was invalid");
		}
		return result;
	}
	
	public static List<BlockType> createRandomBlocksTypes(int number, int maxWidth, int maxHeight){
		List<BlockType> result = new ArrayList<BlockType>();
		for (int i = 0; i < number; i++){
			int width = (int) (1 + Math.round((Math.random()*(maxWidth-1))));
			int height = (int) (1 + Math.round((Math.random()*(maxHeight-1))));	
			Config.p("maxWidth = " + maxWidth);
			Config.p("maxHeight = " + maxHeight);
			Config.p("width = " + width);
			Config.p("height = " + height);
			BlockType nb = null;
			int count = 0;
			while (nb == null || result.contains(nb)) {
				count++;
				nb = new BlockType(makeBlock(width,height));
				if (count % 25 == 0){
					Config.p("Count: " + count);
				}
			}
			result.add(nb);
		}
		return result;
	}
	
	/**
	 * Creates a block with the given width and height
	 * Keeps going recursively until it creates a block with at least one
	 * 1 in the top row, bottom row, left column and right column
	 * @param width
	 * @param height
	 * @return
	 */
	private static int[][] makeBlock(int width, int height){		
		int[][] blockArray = new int[width][height];
		for (int x = 0; x < width; x++){
			for (int y = 0; y < height; y++){
				blockArray[x][y] = (int) Math.round(Math.random());
			}
		}
		//check if the bottom row is empty
		boolean valid = true;
		boolean found = false;
		int count = 0;
		while (!found && count < width){
			found = (blockArray[count][height-1] == 1);
			count++;
		}
		valid = found;
		found = false;
		count = 0;
		while (valid && !found && count < width){
			found = (blockArray[count][0] == 1);
			count++;
		}
		valid = found;
		found = false;
		count = 0;
		while (valid && !found && count < height){
			found = (blockArray[0][count] == 1);
			count++;
		}
		valid = found;
		found = false;
		count = 0;
		while (valid && !found && count < height){
			found = (blockArray[width-1][count] == 1);
			count++;
		}
		if (!valid) {
			blockArray = makeBlock(width, height);
		}
		return blockArray;
	}
}


